package com.wes.dsptest.camera;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.util.Size;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Spinner;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;

import com.wes.dsptest.R;

import java.util.Arrays;
import java.util.Collections;

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class Camera2Wrapper implements CameraInterface {

    private Context context;
    private CameraManager cameraManager;
    private CameraDevice mCameraDevice;
    private SurfaceView surfaceView;
    private SurfaceHolder surfaceHolder;
    private CameraCaptureSession cameraCaptureSession;
    private CaptureRequest.Builder previewRequestBuilder;
    private final static String TAG = "Camera2Wrapper";
    private Handler cameraHandler;
    private String mCameraId = "0";
    private int width = 1920;
    private int height = 1080;

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public Camera2Wrapper(Context context, SurfaceView surfaceView, String cameraId) {
        this.context = context;
        this.surfaceView = surfaceView;
        this.mCameraId = cameraId;

        cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);

        if (surfaceView != null) {
            surfaceHolder = surfaceView.getHolder();
            surfaceHolder.addCallback(new SurfaceHolder.Callback() {
                @Override
                public void surfaceCreated(SurfaceHolder holder) {
                    openCamera(mCameraId);
                }

                @Override
                public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

                }

                @Override
                public void surfaceDestroyed(SurfaceHolder holder) {

                }
            });
        }
    }


    public String[] getCameraId() {
        try {
            for (String cameraId : cameraManager.getCameraIdList()) {
                Log.i(TAG, "cameraId : " + cameraId);
            }
            return cameraManager.getCameraIdList();
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    public Size[] getCameraSize(String cameraId){
        Size[] sizes = null;
        try {
            if (cameraId != null) {
                StreamConfigurationMap map = cameraManager.getCameraCharacteristics(cameraId)
                        .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                if (map != null) {
                    sizes = map.getOutputSizes(ImageFormat.JPEG);
                    Log.d(TAG, "len:"+sizes.length+"Max image size: " + sizes[0].getWidth() + "x" + sizes[0].getHeight());
                }
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        return sizes;
    }

    public String[] convertSizeToString(Size[] sizes) {
        String[] result = new String[sizes.length];
        for (int i = 0; i < sizes.length; i++) {
            result[i] = sizes[i].toString();
        }
        return result;
    }


    public void setCameraId(String id){
        this.mCameraId = id;
    }

    public void setCameraSize(String size){
        String[] sizeStrArray = size.split("x");
        if (sizeStrArray.length == 2) {
            width = Integer.parseInt(sizeStrArray[0]);
            height = Integer.parseInt(sizeStrArray[1]);
            Log.i(TAG, "set Camera size width:" +width+" height:"+height);
        }
    }

    private CameraDevice.StateCallback deviceCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice cameraDevice) {
            mCameraDevice = cameraDevice;
            Log.i(TAG, "camera device " + mCameraDevice);
            Log.i(TAG, "camera iD " + mCameraId);
            startPreview();
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice cameraDevice) {
            mCameraDevice = cameraDevice;
            mCameraDevice.close();
        }

        @Override
        public void onError(@NonNull CameraDevice cameraDevice, int i) {
            Log.e(TAG, "camera open failed " + i);
            mCameraDevice = cameraDevice;
            mCameraDevice.close();
            mCameraDevice = null;

        }
    };


    @Override
    public void openCamera(String cameraId) {
        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            return;
        }

        try {
            cameraManager.openCamera(mCameraId, deviceCallback, null);
            Log.i(TAG, "camera openCamera ");
        } catch (CameraAccessException e) {
            Log.e(TAG, "camera openCamera failed ");
            e.printStackTrace();
        }

    }

    @Override
    public void startPreview() {

        try {
            previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            previewRequestBuilder.addTarget(surfaceHolder.getSurface());
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            try {
                mCameraDevice.createCaptureSession(Arrays.asList(surfaceHolder.getSurface()), new CameraCaptureSession.StateCallback() {
                    @Override
                    public void onConfigured(@NonNull CameraCaptureSession session) {
                        cameraCaptureSession = session;
                        CaptureRequest captureRequest = previewRequestBuilder.build();
                        try {
                            cameraCaptureSession.setRepeatingRequest(captureRequest, null, cameraHandler);
                        } catch (CameraAccessException e) {
                            Log.e(TAG, "cameraCaptureSession访问摄像头失败");
                        }
                    }

                    @Override
                    public void onConfigureFailed(@NonNull CameraCaptureSession session) {

                    }
                }, null);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void stopPreview() {

    }

    @Override
    public void closeCamera() {
        if(cameraCaptureSession != null) {
            cameraCaptureSession.close();
            cameraCaptureSession = null;
        }
        if(mCameraDevice != null) {
            mCameraDevice.close();
            mCameraDevice = null;
        }


        if(cameraHandler != null) {
            cameraHandler.getLooper().quitSafely();
            cameraHandler = null;
        }
    }


    @Override
    public void setPreviewCallback(PreviewCallback callback) {

    }
}
